package weaver.interfaces.sso.oauth2;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.engine.integration.util.HttpsUtil;
import org.apache.commons.lang.StringUtils;
import weaver.formmode.util.UrlUtil;
import weaver.general.Util;
import weaver.hrm.User;
import weaver.integration.cache.OAuth2ConfigCache;
import weaver.integration.logging.Logger;
import weaver.integration.logging.LoggerFactory;
import weaver.integration.util.AccountTypeUtils;
import weaver.integration.util.SessionUtil;
import weaver.integration.util.SystemVariableUtils;
import weaver.integration.whitelist.WhiteListHandler;
import weaver.integration.whitelist.WhiteListUtils;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * Created by crazyDream on 2018/9/4.
 * OAuth2单点登录
 */
public class OAuth2SSOLoginFilter implements Filter,WhiteListHandler {

    private Logger logger = LoggerFactory.getLogger(OAuth2SSOLoginFilter.class);

    public void init(FilterConfig filterConfig) throws ServletException {
    }

    public void doFilter(ServletRequest ServletRequest, ServletResponse ServletResponse, FilterChain chain) throws ServletException, IOException {
        HttpServletRequest request = (HttpServletRequest) ServletRequest;
        HttpServletResponse response = (HttpServletResponse) ServletResponse;
        if(handleWhiteList(ServletRequest,ServletResponse,chain)){
            chain.doFilter(ServletRequest, ServletResponse);
            return;
        }
        String contextPath=Util.null2String(request.getContextPath());
        String requestURI1 = request.getRequestURI();
        //运维平台后台静默传code参数导致被调用oauh2解析code的逻辑
        if (requestURI1 != null && requestURI1.indexOf("/join/") == 0) {
            chain.doFilter(ServletRequest, ServletResponse);
            return;
        }
        OAuth2ConfigCache configCache = new OAuth2ConfigCache();
        String isuse = "";
        if (configCache.next()) {
            isuse = configCache.getIsuse();
        }
        if ("1".equals(isuse)) {
            String requestURI = request.getRequestURI();
            String client_id_key = configCache.getClient_id_key();
            String client_id = configCache.getClient_id();
            String client_secret_key = configCache.getClient_secret_key();
            String client_secret = configCache.getClient_secret();
            String access_token_key = configCache.getAccess_token_key();
            String code_key = configCache.getCode_key();
            String redirect_uri_key = configCache.getRedirect_uri_key();
            String ssocode = Util.null2String(request.getParameter(code_key));
            String access_token = Util.null2String(request.getParameter(access_token_key));
            //code和token都没有,直接放行
            if ("".equals(ssocode) && "".equals(access_token)) {
                chain.doFilter(request, response);
                return;
            }
            logger.info("=========requestURI:"+requestURI);
            logger.info("=========requestQuery:"+request.getQueryString());
            String account_type=configCache.getAccount_type();
            String account_key=configCache.getAccount_key();
            String access_token_cfg = configCache.getAccess_token_cfg();
            String profile_cfg = configCache.getProfile_cfg();
            String logout_cfg = configCache.getLogout_cfg();
            String refresh_token_cfg = configCache.getRefresh_token_cfg();
            String heart_beat_cfg = configCache.getHeart_beat_cfg();


            if (!"".equals(ssocode)||!"".equals(access_token)) {
                String currentPage = request.getServletPath().toLowerCase();

                //1,获取access_token
                String ssoToken = "";
                String portStr="";
                int serverPort = request.getServerPort();
                if (serverPort != 80) {
                    portStr = ":" + serverPort;
                }
                String serverName = request.getServerName()+portStr;
                boolean encodeServiceUrl = true;
                String artifactParameterName = access_token_key;
                String serviceUrl = OAuth2AuthenticationFilter.constructServiceUrl(request, response, "", serverName, artifactParameterName, encodeServiceUrl);
                if (serviceUrl != null && serviceUrl.indexOf("&"+code_key+"=")>=0) {
                    serviceUrl = serviceUrl.substring(0, serviceUrl.indexOf("&"+code_key+"="));
                }
                if (serviceUrl != null && (serviceUrl.indexOf("?"+code_key+"=")>=0)) {
                    serviceUrl = serviceUrl.substring(0, serviceUrl.indexOf("?"+code_key+"="));
                }

                JSONObject o = JSON.parseObject(access_token_cfg);
                if (o != null||!"".equals(access_token)) {
                    //上下文变量
                    Map<String, Object> replaceParams = new HashMap<>();
                    replaceParams.putAll(SystemVariableUtils.getTimestampVariables());
                    replaceParams.put(client_id_key, configCache.getClient_id());
                    replaceParams.put(client_secret_key, configCache.getClient_secret());
                    replaceParams.put(code_key, ssocode);
                    replaceParams.put(redirect_uri_key, URLEncoder.encode(serviceUrl, "UTF-8"));
                    String other_params = configCache.getOther_params();//其他参数
                    if (other_params != null && other_params.length() > 0) {
                        //JSONObject oo = JSON.parseObject(other_params);
                        JSONArray other_para = JSON.parseArray(other_params);
                        if (other_para != null&&other_para.size()>0) {
                            int len = other_para.size();
                            for (int i = 0; i < len; i++) {
                                JSONObject jsonObject = other_para.getJSONObject(i);
                                replaceParams.put(jsonObject.getString("paramKey"), jsonObject.getString("paramValue"));
                            }
                        }
                    }
                    String result = "";
                    if ("".equals(access_token)) {
                        String access_token_url = Util.null2String(o.getString("access_token_url"));
                        String access_token_method = Util.null2String(o.getString("access_token_method")).equals("1") ? "GET" : "POST";
                        JSONArray header = o.getJSONArray("access_token_header");
                        JSONArray params = o.getJSONArray("access_token_params");

                        //==============================派拉方案==============================
                        boolean isParaScheme = SchemeUtils.isParaScheme(params);
                        if (isParaScheme) {
                            SchemeUtils.generateParaAccessTokenParams(replaceParams,client_id,client_secret,ssocode,serviceUrl);
                        }
                        //==============================派拉方案==============================

                        result = HttpsUtil.getResult(header,params,access_token_url,access_token_method,replaceParams);
                    }

                    if (JSON.isValidObject(result) || !"".equals(access_token) || (result != null && result.indexOf(access_token_key) >= 0)) {
                        if ("".equals(access_token)) {
                            if (JSON.isValidObject(result)) {
                                //JSON解析
                                JSONObject jsonObject = JSONObject.parseObject(result);
                                if (jsonObject != null && jsonObject.size() > 0) {
                                    ssoToken = jsonObject.getString(access_token_key);
                                    Set<Map.Entry<String, Object>> entrySet = jsonObject.entrySet();
                                    for (Map.Entry<String, Object> entry : entrySet) {
                                        replaceParams.put(entry.getKey(), "" + entry.getValue());
                                    }
                                }
                            } else {
                                //支持字符串返回的模式(目前遇到的有派拉)，如：access_token=TGT-1-bVMN764IeAa5eaSMfBgAcIzvvh7DznaQ2QHqV70tMgnOQxI2zs-113.105.152.174&expires=7073e
                                if (result.indexOf("?") == -1) {
                                    result = "?" + result;
                                }
                                Map<String, String> map = UrlUtil.URLRequest(result);
                                ssoToken = (String) map.get(access_token_key);
                                for (Map.Entry<String, String> entry : map.entrySet()) {
                                    replaceParams.put(entry.getKey(), "" + entry.getValue());
                                }
                            }
                        } else {
                            ssoToken = access_token;
                        }

                        if (ssoToken != null && ssoToken.length() > 0) {
                            //2,获取账号
                            replaceParams.put(access_token_key, ssoToken);
                            String ssologinid = "";
                            JSONObject oo = JSON.parseObject(profile_cfg);
                            if (oo != null) {
                                String profile_url = Util.null2String(oo.getString("profile_url"));
                                String profile_account_customsql = Util.null2String(oo.getString("profile_account_customsql"));
                                String profile_method = Util.null2String(oo.getString("profile_method")).equals("1") ? "GET" : "POST";
                                JSONArray profile_header = oo.getJSONArray("profile_header");
                                JSONArray profile_params = oo.getJSONArray("profile_params");

                                //==============================派拉方案==============================
                                boolean isParaScheme = SchemeUtils.isParaScheme(profile_params);
                                if (isParaScheme) {
                                    SchemeUtils.generateParaProfileParams(replaceParams, client_id, client_secret, ssoToken);
                                }
                                //==============================派拉方案==============================

                                String resultt = HttpsUtil.getResult(profile_header, profile_params, profile_url, profile_method, replaceParams);
                                if (JSON.isValidObject(resultt)) {
                                    JSONObject jsonObject = JSONObject.parseObject(resultt);
                                    logger.info(">>>>>>>>>>>>>>>jsonObject="+jsonObject);
                                    String entities = jsonObject.getString( "entities" );
                                    logger.info(">>>>>>>>>>>>>>>entities="+entities);
                                    String entitie = StringUtils.strip(entities.toString(),"[]");
                                    logger.info(">>>>>>>>>>>>>>>entitie="+entitie);
                                    JSONObject jsonObject1 = JSONObject.parseObject(entitie);
                                    logger.info(">>>>>>>>>>>>>>>jsonObject1="+jsonObject1);
                                    ssologinid = jsonObject1.getString( "account" );
                                    //ssologinid = Util.null2String(AccountTypeUtils.getValueByJSONPath(jsonObject1, account_key));
                                    logger.info(">>>>>>>>>>>>>>>ssologinid="+ssologinid);
                                    if (!ssologinid.equals("")) {
                                        //1,获取UserId
                                        Map<String, Object> params1 = new HashMap<>();
                                        params1.put("accountType", AccountTypeUtils.accountTypes.get(account_type));
                                        params1.put("loginType", SessionUtil.getLoginType(request));
                                        params1.put("principalName", ssologinid);
                                        params1.put("customSQL", AccountTypeUtils.getFixedCustomSQLByJSONObject(jsonObject1, profile_account_customsql));
                                        String userId = SessionUtil.getUserIdByRule(params1);
                                        User user_new = null;
                                        if (!"".equals(userId)) {
                                            User user = (User) request.getSession(true).getAttribute("weaver_user@bean");
                                            String istest = Util.null2String((String) request.getSession(true).getAttribute("istest"));

                                            Calendar today = Calendar.getInstance();
                                            String currentdate = Util.add0(today.get(Calendar.YEAR), 4) + "-" + Util.add0(today.get(Calendar.MONTH) + 1, 2) + "-" + Util.add0(today.get(Calendar.DAY_OF_MONTH), 2);

                                            if (user == null || user != null && !"1".equals(istest) && !user.getLoginid().toLowerCase().equals(ssologinid)) {
                                                //2,构造User
                                                Map<String, Object> retMap = (Map<String, Object>) SessionUtil.createSession(userId, request, response);
                                                //log.info("=====retMap:"+ JSON.toJSONString(retMap));
                                                User createdUser = (User) request.getSession(true).getAttribute("weaver_user@bean");
                                                if (createdUser == null) {
                                                    //创建用户失败
                                                    //3,license判断
                                                    if (retMap != null) {
                                                        Object isLicense1 = retMap.get("isLicense");
                                                        //log.info("==============isLicense1 !!"+isLicense1);
                                                        if (isLicense1 != null) {
                                                            boolean isLicense = (boolean) isLicense1;
                                                            if (!isLicense) {
                                                                String licenseUrl = Util.null2String(retMap.get("licenseUrl"));
                                                                String requestURI11 = Util.null2String(request.getRequestURI());
                                                                if (!licenseUrl.toLowerCase().equals(requestURI11.toLowerCase())) {
                                                                    response.sendRedirect(licenseUrl);
                                                                    return;
                                                                }

                                                            }
                                                        }
                                                    }

                                                    response.getWriter().println(ssologinid + " is not found in this system, please contact the system manager to check the account.");
                                                    return;


                                                }

                                                logger.info("============session create success");
                                                if (retMap != null) {
                                                    //第一次修改密码
                                                    Object changePassword = retMap.get("changePassword");
                                                    if (changePassword != null) {
                                                        boolean isLicense = (boolean)changePassword ;
                                                        if (isLicense) {
                                                            String licenseUrl = Util.null2String(retMap.get("passwordUrl"));
                                                            String requestURI11 = Util.null2String(request.getRequestURI());
                                                            if (!licenseUrl.toLowerCase().equals(requestURI11.toLowerCase())) {
                                                                response.sendRedirect(licenseUrl);
                                                                return;
                                                            }

                                                        }
                                                    }
                                                }
                                                //4,cookie处理
                                                SessionUtil.setCookie(request, response);
                                            } else {
                                                user_new = user;
                                                user_new.setLastlogindate(currentdate);
                                            }
                                            if (currentPage.indexOf("/login.jsp") > -1 || currentPage.indexOf("/verifylogin.jsp") > -1 || currentPage.indexOf("/refresh.jsp") > -1) {
                                                response.sendRedirect(SessionUtil.getHomePageAfterLogin(request, response));
                                                return;
                                            }

                                            if ("/".equals(requestURI)) {
                                                response.sendRedirect(contextPath+"/wui/index.html#/main");
                                                return;
                                            }

                                            String from =Util.null2String( request.getParameter("from"));
                                            boolean isPortalBackstage = "backstage".equalsIgnoreCase(from);//门户后台的配置页面
                                            if (!isPortalBackstage && requestURI != null && requestURI.contains("/spa/portal/static4mobilelogin/index.html")) {
                                                //移动端登录,做跳转
                                                logger.info("===========移动端登录...");
                                                String cas_redirect_home_url = "/spa/hrm/static4sso/index.html";
                                                response.sendRedirect(contextPath+cas_redirect_home_url);
                                                return;
                                            }

                                        } else {
                                            logger.error("==========accountType:" + account_type + ",accountValue:" + ssologinid + " is not found in OA!!! please check the account!!!");
                                            //response.sendRedirect("/wui/index.html");
                                            response.getWriter().println(ssologinid + " is not found in this system, please contact the system manager to check the account.");
                                            return;
                                        }

                                    } else {
                                        response.getWriter().println("this account is not found in this system, please contact the system manager to check the account.");
                                        return;
                                    }
                                }

                            }
                        }
                    }
                }
            }

        }


        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {

    }

    @Override
    public boolean handleWhiteList(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
        return WhiteListUtils.isWhite(request,getClass().getName());
    }
}
